package com.block.match.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.CountInfoDTO;
import com.block.common.service.IApplicationInfoService;
import com.block.common.service.IChannelCommonService;
import com.block.common.service.IMerchantCommonService;
import com.block.common.service.LogFactory;
import com.block.common.service.merchant.IMerchantThirdBaseInfoService;
import com.block.common.vo.ResponseVo;
import com.block.datapush.factory.PushExtDataFactory;
import com.block.datapush.model.ProtocolInfoEntity;
import com.block.db.entity.*;
import com.block.db.mapper.DataMatchOrderItemMapper;
import com.block.db.mapper.MemberSourceInfoMapper;
import com.block.match.constant.DataMatchConstant;
import com.block.match.enums.OrderStatusEnum;
import com.block.match.model.dto.MatchOrderResultDTO;
import com.block.match.model.vo.MatchOrderItem;
import com.block.match.model.vo.MatchOrderVO;
import com.block.match.model.vo.MatchResultVO;
import com.block.match.service.IDataMatchOrderInfoService;
import com.block.match.service.IMatchHandleService;
import com.block.merchant.model.dto.MerchantOrderDTO;
import com.block.merchant.model.result.DataMatchResult;
import com.block.merchant.model.result.MatchMerchantInfo;
import com.block.merchant.model.vo.MerchantAbiBDataPushInfoVO;
import com.block.merchant.service.IDataMerchantPushService;
import com.block.merchant.service.IMerchantBaseInfoService;
import com.block.merchant.service.IMerchantTaskInfoService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

@Service
public class MatchHandleService implements IMatchHandleService {

    private static final Logger log = LogFactory.getCommLog();

    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    IDataMatchOrderInfoService dataMatchOrderInfoService;
    @Autowired
    IDataMerchantPushService dataMerchantPushService;
    @Autowired
    IMerchantCommonService merchantCommonService;
    @Resource
    MemberSourceInfoMapper memberSourceInfoMapper;
    @Autowired
    IMerchantTaskInfoService merchantTaskInfoService;
    @Autowired
    IMerchantBaseInfoService merchantBaseInfoService;
    @Resource
    DataMatchOrderItemMapper dataMatchOrderItemMapper;
    @Autowired
    IApplicationInfoService applicationInfoService;
    @Autowired
    IMerchantThirdBaseInfoService merchantThirdBaseInfoService;


    @Autowired
    IChannelCommonService channelCommonService;


    /**
     * 用户信息匹配
     * <p>
     * 每个进来的用户都会产生一个匹配记录
     */
//    @Override
//    public MatchResultVO getMatchResult(MemberSourceInfo memberSourceInfo) {
//
//        try {
//            CountDownLatch countDownLatch = new CountDownLatch(1);
//            Future<MatchResultVO> merchantInfoFuture = ThreadUtil.execAsync(new Callable<MatchResultVO>(){
//                @Override
//                public MatchResultVO call() throws Exception {
//
//                    MatchResultVO matchResultVO = getMatchResult0(memberSourceInfo);
//                    countDownLatch.countDown();
//                    return matchResultVO;
//                }
//            });
//
//            // 撞库时间
//            countDownLatch.await(4000, TimeUnit.MILLISECONDS);
//
//            if (merchantInfoFuture.isDone()){
//                MatchResultVO matchResultVO = merchantInfoFuture.get();
//                return matchResultVO;
//            }
//
////            System.out.println("撞库超时=====================");
//
//        }catch (Exception exception){
//            exception.printStackTrace();
//            String message = StrUtil.format("【channelCode】{}【channelName】{}【uid】{}",
//                    memberSourceInfo.getChannelCode(), memberSourceInfo.getChannelName(), memberSourceInfo.getUid());
//            notifyExceptionService.notifyNoticeInfo("MEMBER_CHECK_EXC", "撞库操作异常", message, exception);
//
//        }
//        return null;
//    }


    @Override
    public MatchResultVO getMatchResult0(MemberSourceInfo memberSourceInfo) {
        try {
            /**
             * 初始化匹配订单信息
             */
            DataMatchOrderInfo dataMatchOrderInfo = dataMatchOrderInfoService.initMatchOrderInfo(memberSourceInfo);

            MatchResultVO matchResultVO = new MatchResultVO();
            matchResultVO.setOrderId(String.valueOf(dataMatchOrderInfo.getId()));

            // 条件过滤
            DataMatchResult dataMatchResult = dataMerchantPushService.dataMatchHandle(memberSourceInfo);
            if (dataMatchResult.getMatchSize() == 0) {
                matchResultVO.setMatchSuccess(false);

                DataMatchOrderInfo updateOrder = new DataMatchOrderInfo();
                updateOrder.setId(dataMatchOrderInfo.getId());
                updateOrder.setStatus(OrderStatusEnum.FAILED.getValue());
                updateOrder.setMessage("没有匹配到合适的商户信息");
                dataMatchOrderInfoService.updateById(updateOrder);

                log.info("【客户信息匹配】匹配完成，没有匹配到合适的商户【orderId】{}", dataMatchOrderInfo.getId());
                return matchResultVO;
            }

            dataMatchResult.setMatchOrderId(dataMatchOrderInfo.getId());
            dataMatchResult.setUid(memberSourceInfo.getUid());

            /**
             * 根据匹配结果，更新匹配订单信息
             */
            List<MatchOrderResultDTO> resultDTOList =
                    dataMatchOrderInfoService.saveMatchOrderResult(dataMatchResult, dataMatchOrderInfo, memberSourceInfo);
            
            /**
             * 撞库成功总计
             */
            CountInfoDTO countInfoDTO = new CountInfoDTO();
            countInfoDTO.setChannelCode(memberSourceInfo.getChannelCode());
            if (resultDTOList != null && !resultDTOList.isEmpty()) {
                countInfoDTO.setMatchSuccessCount(1);
                countInfoDTO.setMatchSuccessNumber(resultDTOList.size());
            }else {
                countInfoDTO.setWuYongCount(1);
            }
            channelCommonService.updateChannelCount(countInfoDTO);

            // 组装返回信息

            matchResultVO.setMatchSuccess(true);
            matchResultVO.setOrderProtocolUrl(StrUtil.format(DataMatchConstant.PAGE_APPROVE_URI, dataMatchOrderInfo.getId()));
            List<MatchOrderItem> orderItemList = new ArrayList<>();
            for (MatchOrderResultDTO orderResultDTO : resultDTOList) {
                MatchOrderItem matchOrderItem = new MatchOrderItem();
                matchOrderItem.setOrderItemId(String.valueOf(orderResultDTO.getOrderItemId()));

                MatchMerchantInfo matchMerchantInfo = orderResultDTO.getMatchMerchantInfo();
                matchOrderItem.setInfoType(matchMerchantInfo.getInfoType());
                matchOrderItem.setApproveFlag(matchMerchantInfo.getApproveFlag());
                matchOrderItem.setApproveUrl(matchMerchantInfo.getApproveUrl());
                matchOrderItem.setProtocolUrl(matchMerchantInfo.getProtocolUrl());

                // 查询机构信息
                MerchantBaseInfo merchantBaseInfo = merchantCommonService.getMerchantBaseInfo(matchMerchantInfo.getInfoId());
                matchOrderItem.setCompanyName(merchantBaseInfo.getCompanyName());
                matchOrderItem.setCompanyShortName(merchantBaseInfo.getCompanyShortName());
                matchOrderItem.setCompanyTitle(merchantBaseInfo.getCompanyTitle());
                matchOrderItem.setCompanySubTitle(merchantBaseInfo.getCompanySubTitle());

                matchOrderItem.setCompanyLogo(merchantBaseInfo.getCompanyLogo());
                matchOrderItem.setMaxLoanAmount(merchantBaseInfo.getMaxLoanAmount());
                matchOrderItem.setMaxRate(merchantBaseInfo.getMaxRate());
                matchOrderItem.setMinRate(merchantBaseInfo.getMinRate());

                orderItemList.add(matchOrderItem);
            }
            matchResultVO.setOrderItemList(orderItemList);

            return matchResultVO;
        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("MATCH_MERCHANT", "资质匹配异常", "uid:"+memberSourceInfo.getUid(), exception);
        }
        return null;
    }

    @Override
    public ResponseVo getMatchOrderInfo(String orderNo) {

        DataMatchOrderInfo matchOrderInfo = dataMatchOrderInfoService.getById(orderNo);
        if (ObjectUtil.isEmpty(matchOrderInfo)){
            return new ResponseVo(AppRspCodeConstant.DATA_INFO_NULL, "订单信息为空");
        }

        List<DataMatchOrderItem> orderItemList = dataMatchOrderItemMapper.getEntityListByOrderNoExt(orderNo);
        if (CollUtil.isEmpty(orderItemList)){
            return new ResponseVo(AppRspCodeConstant.DATA_INFO_NULL, "子订单信息为空");
        }

        DataMatchOrderItem matchOrderItem = orderItemList.get(0);

        MatchOrderVO matchOrderVO = new MatchOrderVO();
        matchOrderVO.setOrderNo(orderNo);
        matchOrderVO.setOrderItemNo(String.valueOf(matchOrderItem.getId()));


        ApplicationInfo applicationInfo = applicationInfoService.getAppInfoByAppCode(matchOrderInfo.getAppCode());

        // 平台协议地址
        String ownerProtocolUrl = StrUtil.format("{}page/newprotocol/{}/{}.html", applicationInfo.getApiUrl(), matchOrderVO.getOrderNo(), matchOrderVO.getOrderItemNo());

        MerchantBaseInfo merchantBaseInfo = merchantBaseInfoService.getById(matchOrderItem.getInfoId());
        MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.selectById(matchOrderItem.getUid());
        JSONObject extObject = new JSONObject();
        extObject.put("orderNo", orderNo);
        extObject.put("orderItemNo", String.valueOf(matchOrderItem.getId()));

        // 机构协议地址
        // 如果机构没有协议地址，则使用平台的协议地址
        List<ProtocolInfoEntity> protocolList = PushExtDataFactory.getService(merchantBaseInfo.getFactoryType())
                .getProtocolUrl(merchantBaseInfo, memberSourceInfo, extObject);
        if (CollUtil.isEmpty(protocolList)) {
            ProtocolInfoEntity infoEntity = new ProtocolInfoEntity();
            infoEntity.setProtocolUrl(ownerProtocolUrl);
            infoEntity.setProtocolName("授权协议");
            protocolList.add(infoEntity);
        }

        matchOrderVO.setOwnerProtocolUrl(ownerProtocolUrl);
        matchOrderVO.setOtherProtocolUrl(protocolList);


        if (StrUtil.equals(merchantBaseInfo.getInfoType(), InfoTypeEnum.APIS.getValue())){
            // 查询
            String pushId = matchOrderItem.getPushId();
            MerchantThirdBaseInfo thirdBaseInfo = merchantThirdBaseInfoService.selectEntityByOrderNo(pushId);
            matchOrderVO.setCompantName( thirdBaseInfo.getCompanyName());
            matchOrderVO.setCompantShortName( thirdBaseInfo.getProductName());
            matchOrderVO.setCompantTitle( thirdBaseInfo.getBusinessInfo());
            matchOrderVO.setCompantSubTitle( thirdBaseInfo.getBusinessInfo());
            matchOrderVO.setCompantLogo(thirdBaseInfo.getCompanyLogo());
            matchOrderVO.setMaxLoanAmount( thirdBaseInfo.getMaxLoanAmount());
            matchOrderVO.setMaxRate( thirdBaseInfo.getMaxLoanRate());
            matchOrderVO.setMinRate( thirdBaseInfo.getMinLoanRate());
        }else{
            matchOrderVO.setCompantName( merchantBaseInfo.getCompanyName());
            matchOrderVO.setCompantShortName( merchantBaseInfo.getCompanyShortName());
            matchOrderVO.setCompantTitle( merchantBaseInfo.getCompanyTitle());
            matchOrderVO.setCompantSubTitle(merchantBaseInfo.getCompanySubTitle());
            matchOrderVO.setCompantLogo( merchantBaseInfo.getCompanyLogo());
            matchOrderVO.setMaxLoanAmount(merchantBaseInfo.getMaxLoanAmount());
            matchOrderVO.setMaxRate(merchantBaseInfo.getMaxRate());
            matchOrderVO.setMinRate( merchantBaseInfo.getMinRate());
        }

        return new ResponseVo(AppRspCodeConstant.SUCCESS, matchOrderVO);
    }

    /**
     * 处理商户的手动推送
     * @param infoId
     * @param uid
     * @return
     */
    @Override
    public ResponseVo handlePushManual(String infoId, String uid){
        try {
            // 获取可推送的任务列表
            MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.selectById(Long.valueOf(uid));
            List<MerchantTaskInfo> pushTaskList = merchantTaskInfoService.getMerchantCanPushTaskList(infoId, memberSourceInfo);
            if (ObjectUtil.isEmpty(pushTaskList)){
                return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "无满足该条数据的推送任务（包括账户余额不足）");
            }

            MerchantTaskInfo merchantTaskInfo = pushTaskList.get(0);

            MerchantOrderDTO merchantOrderDTO = new MerchantOrderDTO();
            merchantOrderDTO.setInfoId(merchantTaskInfo.getInfoId());
            merchantOrderDTO.setTaskId(merchantTaskInfo.getId());
            merchantOrderDTO.setPriceAmount(merchantTaskInfo.getPriceAmount());
            merchantOrderDTO.setCostAmount(merchantTaskInfo.getCostAmount());
            merchantOrderDTO.setPayAmount(merchantTaskInfo.getPayAmount());

            MatchMerchantInfo matchMerchantInfo = merchantBaseInfoService.matchWithMerchant(merchantOrderDTO, memberSourceInfo);
            if (!matchMerchantInfo.isMatchSuccess()){
                return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "撞库失败；不可以推送");
            }

            // 保存 推送订单以及推送订单 子信息
            // 并推送
            boolean b = dataMatchOrderInfoService.handleManualToPush(memberSourceInfo, merchantTaskInfo, matchMerchantInfo);
            if (b){
                return new ResponseVo(AppRspCodeConstant.SUCCESS);
            }
            return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "推送失败");

        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("MERCHANT_PUSH_MANUAL", "商户数据手动推送", "uid:"+uid+";infoId:"+infoId, exception);
        }
        return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "推送异常");
    }

    @Override
    public ResponseVo PushApBManual(String infoId, String uid) {
        try {
            // 获取可推送的任务列表
            MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.selectById(Long.valueOf(uid));


            List<MerchantTaskInfo> pushTaskList = merchantTaskInfoService.getMerchantCanPushTaskList(infoId, memberSourceInfo);
            if (ObjectUtil.isEmpty(pushTaskList)){
                return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "无满足该条数据的推送任务（包括账户余额不足）");
            }

            MerchantTaskInfo merchantTaskInfo = pushTaskList.get(0);

            MerchantOrderDTO merchantOrderDTO = new MerchantOrderDTO();
            merchantOrderDTO.setInfoId(merchantTaskInfo.getInfoId());
            merchantOrderDTO.setTaskId(merchantTaskInfo.getId());
            merchantOrderDTO.setPriceAmount(merchantTaskInfo.getPriceAmount());
            merchantOrderDTO.setCostAmount(merchantTaskInfo.getCostAmount());
            merchantOrderDTO.setPayAmount(merchantTaskInfo.getPayAmount());

            MatchMerchantInfo matchMerchantInfo = merchantBaseInfoService.matchWithMerchant(merchantOrderDTO, memberSourceInfo);
            if (!matchMerchantInfo.isMatchSuccess()){
                return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "撞库失败；不可以推送");
            }

            // 保存 推送订单以及推送订单 子信息
            // 并推送
            MerchantAbiBDataPushInfoVO merchantAbiBDataPushInfoVO = dataMatchOrderInfoService.manualApiBPush(memberSourceInfo, merchantTaskInfo, matchMerchantInfo);
            if (merchantAbiBDataPushInfoVO.getStatus()){
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("merchantAbiBDataPushInfoVO",merchantAbiBDataPushInfoVO);
                return new ResponseVo(AppRspCodeConstant.SUCCESS,jsonObject);
            }
            return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "推送失败");

        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("MERCHANT_PUSH_MANUAL", "商户数据手动推送", "uid:"+uid+";infoId:"+infoId, exception);
        }
        return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "推送异常");
    }

    @Override
    public ResponseVo againMatchMerchant(Long uid) {

        MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.selectById(uid);
        MatchResultVO matchResult = this.getMatchResult0(memberSourceInfo);

        if (ObjectUtil.isEmpty(matchResult)){
            matchResult = new MatchResultVO();
            matchResult.setMatchSuccess(false);
        }

        return new ResponseVo(AppRspCodeConstant.SUCCESS, matchResult);
    }

}
